package com.seray.zebraprintlib;

import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;

import com.seray.zebraprintlib.back.PrintCallback;
import com.seray.zebraprintlib.back.PrintException;
import com.seray.zebraprintlib.back.PrinterRequestPermissionCallback;
import com.seray.zebraprintlib.back.RequestPermissionResult;
import com.seray.zebraprintlib.base.BaseLabel;
import com.zebra.sdk.comm.Connection;
import com.zebra.sdk.comm.ConnectionException;
import com.zebra.sdk.printer.discovery.DiscoveredPrinterUsb;
import com.zebra.sdk.printer.discovery.UsbDiscoverer;

import java.util.List;

/**
 * Author：李程
 * CreateTime：2018/8/7 20:48
 * E-mail：licheng@kedacom.com
 * Describe：斑马打印服务
 */
public class ZebraPrintService extends Service {

    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
    private IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
    private PendingIntent mPermissionIntent;
    private boolean hasPermissionToCommunicate = false;
    private UsbManager mUsbManager;
    private DiscoveredPrinterUsb discoveredPrinterUsb;
    private PrinterRequestPermissionCallback permissionCallback;
    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if (device != null) {
                            hasPermissionToCommunicate = true;
                            if (permissionCallback != null)
                                permissionCallback.printerRequestPermissionResult(new RequestPermissionResult(true, getString(R.string.connect_success)));
                        } else {
                            if (permissionCallback != null)
                                permissionCallback.printerRequestPermissionResult(new RequestPermissionResult(false, getString(R.string.connect_failed)));
                        }
                    }
                }
            }
        }
    };
    private Handler mHandler = new Handler(Looper.getMainLooper());

    @Override
    public void onCreate() {
        super.onCreate();
        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
        mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
        registerReceiver(mUsbReceiver, filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mUsbReceiver);
        mHandler.removeCallbacksAndMessages(null);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new PrintBinder();
    }

    public class PrintBinder extends Binder {

        public void requestPermission(final PrinterRequestPermissionCallback callback) {
            permissionCallback = callback;
            new Thread(() -> {
                UsbDiscoveryHandler handler = new UsbDiscoveryHandler();
                UsbDiscoverer.findPrinters(getApplicationContext(), handler);
                try {
                    while (!handler.discoveryComplete) {
                        Thread.sleep(100);
                    }
                    if (handler.printers != null && handler.printers.size() > 0) {
                        discoveredPrinterUsb = handler.printers.get(0);
                        if (!mUsbManager.hasPermission(discoveredPrinterUsb.device)) {
                            mUsbManager.requestPermission(discoveredPrinterUsb.device, mPermissionIntent);
                        } else {
                            hasPermissionToCommunicate = true;
                            mHandler.post(() -> {
                                if (permissionCallback != null)
                                    permissionCallback.printerRequestPermissionResult(new RequestPermissionResult(true, getString(R.string.connect_success)));
                            });
                        }
                    }
                } catch (Exception e) {
                    mHandler.post(() -> {
                        if (permissionCallback != null)
                            permissionCallback.printerRequestPermissionResult(new RequestPermissionResult(false, getString(R.string.connect_failed)));
                    });
                }
            }).start();
        }

        public <T> void printLabel(BaseLabel<T> label, PrintCallback<T> callback) {
            if (label == null) {
                if (callback != null)
                    callback.printError(null, new PrintException(0, getString(R.string.print_error_no_english)));
                return;
            }
            T data = label.getBuilder().getData();
            if (data == null) {
                if (callback != null)
                    callback.printError(null, new PrintException(-1, getString(R.string.print_error_empty)));
                return;
            }
            if (hasPermissionToCommunicate) {
                Connection conn = null;
                try {
                    conn = discoveredPrinterUsb.getConnection();
                    conn.open();
                    byte[] bytes = label.format().getBytes();
                    conn.write(bytes);
                    if (callback != null)
                        callback.printSuccess(data);
                } catch (ConnectionException e) {
                    if (callback != null)
                        callback.printError(data, new PrintException(1, e.getMessage()));
                } finally {
                    if (conn != null) {
                        try {
                            conn.close();
                        } catch (ConnectionException e) {
                        }
                    }
                }
            } else {
                if (callback != null)
                    callback.printError(data, new PrintException(0, getString(R.string.print_error_no_permission)));
            }
        }

        public <T> void printLabel(List<BaseLabel<T>> labels, PrintCallback<T> callback) {
            if (hasPermissionToCommunicate) {
                Connection conn = null;
                T data = null;
                try {
                    conn = discoveredPrinterUsb.getConnection();
                    conn.open();
                    for (BaseLabel<T> label : labels) {
                        data = label.getBuilder().getData();
                        byte[] bytes = label.format().getBytes();
                        conn.write(bytes);
                        if (callback != null)
                            callback.printSuccess(data);
                    }
                } catch (ConnectionException e) {
                    if (callback != null)
                        callback.printError(data, new PrintException(1, e.getMessage()));
                } finally {
                    if (conn != null) {
                        try {
                            conn.close();
                        } catch (ConnectionException e) {
                        }
                    }
                }
            } else {
                if (callback != null)
                    callback.printError(null, new PrintException(0, getString(R.string.print_error_no_permission)));
            }
        }
    }
}
